﻿// Spun AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Net;
using System.Text.RegularExpressions;
using System.IO;
using Spun.Utility.Logging;

namespace Spun.Communications.Hosting
{
    public abstract class Host : IDisposable
    {
        public const string HOST_WILDCARD = "+";

        public Host(string HostString, short Port, string VirtualDirectory)
        {
            string UriPrefix = string.Format("http://{0}:{1}/{2}/",
               HostString, Port, VirtualDirectory);

            Listener = new HttpListener();
            Listener.Prefixes.Add(UriPrefix);
            Listener.Start();

            Listener.BeginGetContext(ProcessRequest, null);

            Sync = new object();
        }

        protected abstract void HandleRequest(HttpListenerContext Context);

        protected static void TextResponse(HttpListenerContext Context, int Status, string ResponseBody)
        {
            Context.Response.ContentType = "text/plain";
            Context.Response.StatusCode = Status;
            using (StreamWriter Writer = new StreamWriter(Context.Response.OutputStream))
                Writer.Write(ResponseBody);
        }

        private void ProcessRequest(IAsyncResult ar)
        {
            try
            {
                HttpListenerContext Context = Listener.EndGetContext(ar);

                if (Context == null)
                    return;

                try
                {
                    HandleRequest(Context);
                }
                catch (Exception e)
                {
                    TextResponse(Context, 500, e.Message);
                    Context.Response.Close();
                }
            }
            catch (Exception e)
            {
                lock (Sync)
                    if (!Stopped)
                        LoggingComponent.Logger.LogException(LogLevel.Warn, e);
            }

            lock (Sync)
            {
                if (!Stopped)
                    Listener.BeginGetContext(ProcessRequest, null);
            }
        }

        private HttpListener Listener;
        private object Sync;
        private bool Stopped;

        #region IDisposable Members

        public void Dispose()
        {
            lock (Sync)
            {
                Stopped = true;

                Listener.Close();
            }
        }

        #endregion
    }
}
